<?php
namespace app\queen\controller;
use app\common\model\Redis;
use app\common\model\Aes;
use app\common\model\Dev_info;
use app\common\model\Alarm_info;
use app\common\model\User;
use think\Controller;
class Base extends Controller
{
    protected  $redis;
    protected  $post = array();
    protected  $aes;

    protected  $data_recv_t;
    public function __construct(){
        parent::__construct();

        if(!request()->isPost()){
            exit('NO');
        }

        $this->post = input('post.');
        //判断redis中dev_id是否存在
        $this->redis = new Redis();
        $this->aes = new Aes();

        $this->data_recv_t = time();
        //$this->formatCheck();
	   
        $this->dev_init($this->post['dev_id']);
        $this->redis_update($this->post['dev_id'],$this->post['redis_select']);
        $token = $this->post['token'];
	    $token = str_replace(" ","+",$token);
	    $this->checktoken($this->post['dev_id'],$token,$this->post['redis_select']);
       // file_put_contents("/tmp/log.txt","wwww___\r\n".$b."\r\n\r\n"."---token:".$token."\r\n",FILE_APPEND);
    } 
    
    /**
     * 上传数据格式检查 是否合法
     */
    protected function formatCheck(){
        $version = input('post.v', false, 'strval');
        $dev_id = input('post.dev_id', false, 'strtoupper');
        $load = input('post.load', '', null);
        $token = input('post.token', false, null);
        
        //必须是2.0版本,否则退出
        if($version!=='2.0'){
            exit("NO");
        }

        if(!$load || !$dev_id || !$version){
            exit("NO");
        }
        
        $this->post = $_POST;
    }

    /**
     * 检查redis中是否存在该设备,不存在载入设备信息,若是非法设备号直接退出
     * @param  [string] $dev_id [设备号]
     * @return [bool]
     */
    protected function checkRedis($dev_id){  
        //\Think\Log::write($dev_id."xujun");
        if(!$dev_id){
            return false;
        }

        //检查redis中0号数据库还是2号数据库或者是否存在该设备
        $select = $this->redis->whereRedis($dev_id);
        if($select !== false){
            $this->post['redis_select'] = $select;
            return true;
        }
  
        $devinfoModel = new Dev_info();
        $field = "tz,guid2,key,intv,online_inform,owner,state,encrypt";
        $info = $devinfoModel->getOne(array('guid1'=>$dev_id),$field);
        if($info){

            //设备XML上传若没激活一样可以访问 
            if($info["state"]=="inactive"){
                 if(ACTION_NAME != "devInfoUpload"){
                      return false;
                 }
            }

            $AlarmModel = new Alarm_info();

            $al = $AlarmModel->getOne(["guid1"=>$dev_id],'intv,times_to_send,valid,inform_type,addr');
            if($al){
                //addr若不存在,则默认为 用户名(邮箱)
                if(!$al["addr"]){
                    $userModel = new User();
                    $email_addr = $userModel->getOne(['uid'=>$info["owner"]],'name');
                    $al["addr"] = $email_addr["name"];
                }
            }else{
                $al["intv"] = "60";
                $al["times_to_send"] = "3";
                $al["valid"] = "Y";
                $al["inform_type"] = "email";
                $userModel = new User();
                $email_addr = $userModel->getOne(['uid'=>$info["owner"]],'name');
                $al["addr"] = $email_addr["name"];
            }

            //判断,切换数据库
            if($info["online_inform"]>0){
                //告知设备,2号数据库
                $this->post["redis_select"] = 2;

                $this->redis->select(2);
                $tl = $AlarmModel->getOne(['guid1'=>$dev_id,'alarm_type'=>'offline'],'times_to_send,valid,intv');
                if(!$tl){
                    $tl["times_to_send"] = "3";
                    $tl["valid"] = "Y";
                    $tl["intv"] = "10";
                }

                //过期时间
                $online_inform = $info["online_inform"]*60+30;

                $this->redis->hset($dev_id,"if_save","0");
                $this->redis->hset($dev_id,"last_online_inform_t",$time);
                $this->redis->hset($dev_id,"last_online_send_t","0");
                $this->redis->hset($dev_id,"online_inform_temp_valid","Y");
                $this->redis->hset($dev_id,"online_inform_has_send_num","0");
                $this->redis->hset($dev_id,"online_inform_send_num",$tl["times_to_send"]);
                $this->redis->hset($dev_id,"online_inform_intv",$online_inform);
                $this->redis->hset($dev_id,"online_alarm_intv",$tl["intv"]);
                $this->redis->hset($dev_id,"online_inform_valid",$tl["valid"]);
            }else{
                //非告知设备,0号数据库
                $this->post["redis_select"] = 0;
                $this->redis->select(0);
            }

            $this->redis->hset($dev_id,"server_ip",$_SERVER['SERVER_ADDR']);
            $this->redis->hset($dev_id,"tz",$info["tz"]);
            $this->redis->hset($dev_id,"guid2",$info["guid2"]);
            $this->redis->hset($dev_id,"key",$info["key"]);
            $this->redis->hset($dev_id,"intv",$info["intv"]);
            $this->redis->hset($dev_id,"encrypt",$info['encrypt']);

            $this->redis->hset($dev_id,"cur_alarm_no","-1");
            $this->redis->hset($dev_id,"alarm_msg","");
            $this->redis->hset($dev_id,"last_alarm_inform_t","0");
            $this->redis->hset($dev_id,"alarm_t","0");
            $this->redis->hset($dev_id,"alarm_has_send_num","0");
            $this->redis->hset($dev_id,"alarm_temp_valid","Y");

            $this->redis->hset($dev_id,"alarm_intv",$al["intv"]/60);
            $this->redis->hset($dev_id,"alarm_send_num",$al["times_to_send"]);
            $this->redis->hset($dev_id,"alarm_valid",$al["valid"]);
            $this->redis->hset($dev_id,"inform_type",$al["inform_type"]);
            //将设备所有通知地址存入redis中
            $AlarmModel = new Alarm_info();
            $AlarmModel->addrToRedis($dev_id);            
            //将积累型数据参数id | 操作单位 | 可控操作 存入redis
            $devinfoModel->accumulateRedis($dev_id);
            //将当天数据 存在 redis
            $devinfoModel->dataRedis($dev_id,$info["tz"]);
            return true;
        }else{
            //此设备不存在
            return false;
        }  
    }

    /**
     * XML初始化到redis
     * @param  [string] $dev_id  [设备号]
     * @param  [string] $select1 [需转入的数据库]
     * @param  [string] $select2 [原先所在数据库]
     * @param  [string] $tz      [设备所在时区]
     */
    public function addRedis($dev_id,$select1,$tz){

         $time = time();
         $select2 = false;
         if($select1){
            //应该在2
            $this->redis->select(0);
            $r = $this->redis->isExists($dev_id);
            if($r){
                //原0
                $select2 = 0;
            }else{
                $this->redis->select(2);
                $r = $this->redis->isExists($dev_id);
                if($r){
                    //原2
                    return TRUE;
                }
            }
         }else{
            //应该在0
            $this->redis->select(0);
            $r = $this->redis->isExists($dev_id);
            if($r){
                //原0
                return TRUE;
            }else{
                $this->redis->select(2);
                $r = $this->redis->isExists($dev_id);
                if($r){
                    //原2
                    $select2 = 2;
                }
            }
         }

         $AlarmModel = new Alarm_info();
         $devinfoModel = new Dev_info();

         if(is_bool($select2)){
            //从mysql中获取,直接添加到redis中
            $field = "guid2,key,intv,owner,online_inform,encrypt";

            $info = $devinfoModel->getOne(['guid1'=>$dev_id,'state'=>'active'],$field);
            $al = $AlarmModel->getOne(["guid1"=>$dev_id,"alarm_type"=>"abnormal"],'intv,times_to_send,valid,inform_type,addr');
            if($al){
                //addr若不存在,则默认为 用户名(邮箱)
                if(!$al["addr"]){
                    $userModel = new User();
                    $email_addr = $userModel->getOne(["uid"=>$info["owner"]],"name");
                    $al["addr"] = $email_addr["name"];
                }
            }else{
                $al["intv"] = "10";
                $al["times_to_send"] = "3";
                $al["valid"] = "Y";
                $al["inform_type"] = "email";

                $userModel = new User();
                $email_addr = $userModel->getOne(["uid"=>$info["owner"]],"name");
                $al["addr"] = $email_addr["name"];
            }

            $guid2 = $info["guid2"];
            $key = $info["key"];
            $intv = $info["intv"];
            $alarm_intv = $al["intv"];
            $alarm_send_num = $al["times_to_send"];
            $alarm_valid = $al["valid"];
            $inform_type = $al["inform_type"];
            $inform_addr = $al["addr"];
            $encrypt = $info["encrypt"];

         }else{
            //代表需要切换数据库,从redis获取,则删除原来所在数据库的数据
            $this->redis->select($select2);
            
            $guid2 = $this->redis->hget($dev_id,"guid2");
            $key = $this->redis->hget($dev_id,"key");
            $intv = $this->redis->hget($dev_id,"intv");
            $alarm_intv = $this->redis->hget($dev_id,"alarm_intv");
            $alarm_send_num = $this->redis->hget($dev_id,"alarm_send_num");
            $alarm_valid = $this->redis->hget($dev_id,"alarm_valid");
            $inform_type = $this->redis->hget($dev_id,"inform_type");
            $inform_addr = $this->redis->hget($dev_id,"inform_addr");
            $encrypt = $this->redis->hget($dev_id,"encrypt");
            //删除
            $this->redis->del($dev_id);
         }

         //设置新的
         $this->redis->select($select1);

         $this->redis->hset($dev_id,"server_ip",$_SERVER['SERVER_ADDR']);
         $this->redis->hset($dev_id,"guid2",$guid2);
         $this->redis->hset($dev_id,"key",$key);
         $this->redis->hset($dev_id,"intv",$intv);
         $this->redis->hset($dev_id,"alarm_intv",$alarm_intv);
         $this->redis->hset($dev_id,"alarm_send_num",$alarm_send_num);
         $this->redis->hset($dev_id,"alarm_valid",$alarm_valid);
         $this->redis->hset($dev_id,"inform_type",$inform_type);
         $this->redis->hset($dev_id,"inform_addr",$inform_addr);
         $this->redis->hset($dev_id,"encrypt",$encrypt);
 
         $this->redis->hset($dev_id,"cur_alarm_no","-1");
         $this->redis->hset($dev_id,"alarm_msg","");
         $this->redis->hset($dev_id,"last_alarm_inform_t","0");
         $this->redis->hset($dev_id,"alarm_t","0");
         $this->redis->hset($dev_id,"alarm_has_send_num","0");
         $this->redis->hset($dev_id,"alarm_temp_valid","Y");
 
         //在线告知信息
         if($select1=="2"){
             $tl = $AlarmModel->getOne(["guid1"=>$dev_id,"alarm_type"=>"offline"],"times_to_send,valid,intv");
             if(!$tl){
                 $tl["times_to_send"] = "3";
                 $tl["valid"] = "Y";
                 $tl["intv"] = "600";
             }

             $this->redis->hset($dev_id,"if_save","0");
             $this->redis->hset($dev_id,"last_online_inform_t",$time);
             $this->redis->hset($dev_id,"last_online_send_t","0");
             $this->redis->hset($dev_id,"online_inform_temp_valid","Y");
             $this->redis->hset($dev_id,"online_inform_has_send_num","0");
             $this->redis->hset($dev_id,"online_inform_send_num",$tl["times_to_send"]);
             $this->redis->hset($dev_id,"online_inform_valid",$tl["valid"]);
             $this->redis->hset($dev_id,"online_alarm_intv",$tl["intv"]);
         }

         //将当天数据存在redis
         $devinfoModel->dataRedis($dev_id,$tz);
         //将设备所有通知地址存入redis中
         $AlarmModel->addrToRedis($dev_id);
    }

    /**
     * redis中数据更改
     * @param  [string] $dev_id [设备号]
     * @param  [string] $select [几号数据库]
     */
    protected function redis_update($dev_id,$select){
        
        $flag = false;
        $this->redis->select($select);

        $encrypt = $this->redis->hget($dev_id,"encrypt");

        if(is_bool($encrypt)){
            $flag = true;
        }

        if($flag){
            $devModel = new Dev_info();
            $info = $devModel->getOne(['guid1'=>$dev_id],'encrypt');

            $this->redis->hset($dev_id,"encrypt",$info["encrypt"]);
        }
    }

    /**
     * 设备初始化
     * @param  [string] $dev_id [设备号]
     */
    protected  function dev_init($dev_id){
       $this->checkRedis($dev_id) ? true: exit("NO");
    }

    /**
     * 检验token合法性
     * @param  [string] $dev_id [设备号]
     * @param  [string] $token [token]
     * @param [string] $select [redis几号数据库]
     */
    protected function checktoken($dev_id,$token,$select){

        $this->redis->select($select);

        $r_time =$this->data_recv_t - $this->redis->hget($dev_id,"last_update");
        $intv = $this->redis->hget($dev_id,"intv");
        $guid2 = $this->redis->hget($dev_id,"guid2");
        
        $time = time();
        if($time-$r_time<$intv || 0>=$r_time){
            //上传时间间隔
            // exit("NO");
        }

        //获取key值,进行AES128解密
        $key = $this->redis->hget($dev_id,"key");

        $res = $this->aes->aesDecode($key,$token);
        
        $return = explode("_",$res);


        // if($this->post['dev_id']=="0000rh"){
        //     file_put_contents("/tmp/log.txt","token:".$token."\r\n",FILE_APPEND);
        //     file_put_contents("/tmp/log.txt","guid2:".$return["0"]."\r\n\r\n\r\n",FILE_APPEND);
        // }
        if($return["0"]!=$guid2){
            exit("NO");
        }
        // $d_time = $this->data_recv_t-$token_timestamp;
        // if(0>=$d_time || $d_time>=10){
        //     exit("NO");
        // }      
    }

    /**
     * api检验token合法性
     * @param  [string] $dev_id [设备号]
     * @param  [string] $token [token]
     * @return [boolean]
     */
    protected function apichecktoken($dev_id,$token){
    
        $r_time =$this->data_recv_t - $this->redis->hget($dev_id,"last_update");
        $intv = $this->redis->hget($dev_id,"intv");
        $guid2 = $this->redis->hget($dev_id,"guid2");
        if($r_time>$intv || 0>=$r_time){
            return false;
        }
    
        //获取key值,进行AES128解密
        $key = $this->redis->hget($dev_id,"key");
        $res = $this->aes->decrypt($key,$token,"AES128");
        //拆分token, token=guid2+time
        $token_guid2 = substr($res,0,-10);
        $token_timestamp = substr($res,-10,10);
   
        if($token_guid2!=$guid2){
            return false;
        }
        $d_time = $this->data_recv_t-$token_timestamp;
        if(0>=$d_time || $d_time>=10){
            return false;
        }
        return true;
    }
    
    
    /**
     * 查询设备是否激活
     * @param  [string] $dev_id [设备号]
     * @return boolean
     */
    protected function ifActive($dev_id){
        $devModel = new Dev_info();
        $row = $devModel->getOne(['dev_id'=>$dev_id,'state'=>'inactive'],'*');
        return $row;
    }
}
?>